package gobgp

import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"strings"
	"sync"
	"time"

	"pceservice/pkg/gobgp/api" // 确保这是gobgp/v4生成的API

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/encoding/protojson"
	"gopkg.in/yaml.v3"

	"pceservice/internal/topology"
)

// Config GoBGP客户端配置
type Config struct {
	Address string `yaml:"address"`
}

// Client GoBGP客户端
type Client struct {
	config     Config
	connection *grpc.ClientConn
	client     api.GoBgpServiceClient
	mu         sync.Mutex
}

// NewClient 创建新的GoBGP客户端
func NewClient(config Config) (*Client, error) {
	conn, err := grpc.Dial(
		config.Address,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithBlock(),
		grpc.WithTimeout(5*time.Second),
	)

	if err != nil {
		return nil, fmt.Errorf("连接GoBGP服务器失败: %v", err)
	}

	return &Client{
		config:     config,
		connection: conn,
		client:     api.NewGoBgpServiceClient(conn),
	}, nil
}

// Close 关闭客户端连接
func (c *Client) Close() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.connection != nil {
		c.connection.Close()
		c.connection = nil
	}
}

// SyncTopology 同步拓扑信息
func (c *Client) SyncTopology(ctx context.Context, topoManager *topology.Manager) error {
	// 定期从GoBGP获取L3拓扑信息
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	// 初始同步
	if err := c.fetchAndUpdateTopology(ctx, topoManager); err != nil {
		log.Printf("初始拓扑同步失败: %v", err)
	}

	// 定期同步
	for {
		select {
		case <-ticker.C:
			if err := c.fetchAndUpdateTopology(ctx, topoManager); err != nil {
				log.Printf("拓扑同步失败: %v", err)
			}
		case <-ctx.Done():
			return ctx.Err()
		}
	}
}

// fetchAndUpdateTopology 从GoBGP获取BGP-LS拓扑信息并更新到拓扑管理器
func (c *Client) fetchAndUpdateTopology(ctx context.Context, topoManager *topology.Manager) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.client == nil {
		return errors.New("GoBGP客户端未初始化")
	}

	// 1. 构造BGP-LS查询请求（AFI_LS + SAFI_LS）
	req := &api.ListPathRequest{
		TableType: api.TableType_TABLE_TYPE_LOCAL,
		Family: &api.Family{
			Afi:  api.Family_AFI_LS,
			Safi: api.Family_SAFI_LS,
		},
		SortType: 0, // 按最佳路径排序
	}

	// 2. 发起流式查询
	stream, err := c.client.ListPath(ctx, req)
	if err != nil {
		return fmt.Errorf("发起ListPath请求失败: %w", err)
	}

	// 3. 存储解析后的拓扑数据（节点、链路、前缀）
	var (
		nodes    []*topology.Node   // 假设拓扑管理器的节点类型
		links    []*topology.Link   // 假设拓扑管理器的链路类型
		prefixes []*topology.Prefix // 假设拓扑管理器的前缀类型
	)

	// 4. 循环处理流式响应
	for {
		resp, err := stream.Recv()
		if err != nil {
			if err == io.EOF || status.Code(err) == codes.Canceled {
				break // 流结束，正常退出
			}
			return fmt.Errorf("接收响应失败: %w", err)
		}

		// 跳过空Destination
		if resp.Destination == nil {
			log.Println("跳过空的Destination")
			continue
		}

		// 5. 解析当前响应中的Destination数据
		lsdbEntry, err := parseDestination(resp.Destination)
		if err != nil {
			log.Printf("解析Destination失败: %v，跳过该条目", err)
			continue
		}

		// 6. 根据解析结果分类存储
		switch entry := lsdbEntry.(type) {
		case *nodeEntry:
			nodes = append(nodes, &topology.Node{
				LocalNode:  entry.LocalNode,
				Attributes: entry.Attributes,
			})
		case *linkEntry:
			links = append(links, &topology.Link{
				LocalNode:      entry.LocalNode,
				RemoteNode:     entry.RemoteNode,
				LinkDescriptor: entry.LinkDescriptor,
				Attributes:     entry.Attributes,
			})
		case *prefixEntry:
			prefixes = append(prefixes, &topology.Prefix{
				LocalNode:        entry.LocalNode,
				PrefixDescriptor: entry.PrefixDescriptor,
			})
		}
	}

	// 7. 更新拓扑管理器
	topoManager.UpdateFromGoBGP(nodes, links, prefixes)
	log.Printf("拓扑同步完成: 节点数=%d, 链路数=%d, 前缀数=%d", len(nodes), len(links), len(prefixes))

	return nil
}

// 以下为辅助类型和解析函数，用于结构化解析结果
type (
	nodeEntry struct {
		LocalNode  map[string]interface{}
		Attributes map[string]interface{}
	}
	linkEntry struct {
		LocalNode      map[string]interface{}
		RemoteNode     map[string]interface{}
		LinkDescriptor map[string]interface{}
		Attributes     map[string]interface{}
	}
	prefixEntry struct {
		LocalNode        map[string]interface{}
		PrefixDescriptor map[string]interface{}
	}
)

// parseDestination 解析Destination中的最佳路径和NLRI信息（核心解析逻辑）
func parseDestination(dest *api.Destination) (interface{}, error) {
	// 1. 从Paths中筛选最佳路径（best=true）
	var bestPath *api.Path
	for _, path := range dest.Paths {
		if path != nil && path.Best {
			bestPath = path
			break
		}
	}
	if bestPath == nil {
		return nil, errors.New("未找到最佳路径(best=true)")
	}

	// 2. 解析NLRI类型（oneof字段）
	if bestPath.Nlri == nil || bestPath.Nlri.Nlri == nil {
		return nil, errors.New("路径中NLRI为空")
	}
	nlriType, nlriData, err := parseNLRI(bestPath.Nlri)
	if err != nil {
		return nil, fmt.Errorf("解析NLRI失败: %w", err)
	}

	// 3. 解析Pattrs中的LsAttribute属性
	lsAttr, err := parseLsAttribute(bestPath.Pattrs)
	if err != nil {
		log.Printf("解析LsAttribute警告: %v（使用默认空属性）", err)
		lsAttr = map[string]interface{}{"node": nil, "link": nil, "prefix": nil}
	}

	// 4. 根据NLRI类型返回对应结构
	switch nlriType {
	case "LsNodeNLRI":
		return &nodeEntry{
			LocalNode:  nlriData["localNode"].(map[string]interface{}),
			Attributes: lsAttr,
		}, nil
	case "LsLinkNLRI":
		return &linkEntry{
			LocalNode:      nlriData["localNode"].(map[string]interface{}),
			RemoteNode:     nlriData["remoteNode"].(map[string]interface{}),
			LinkDescriptor: nlriData["linkDescriptor"].(map[string]interface{}),
			Attributes:     lsAttr,
		}, nil
	case "LsPrefixV4NLRI":
		return &prefixEntry{
			LocalNode:        nlriData["localNode"].(map[string]interface{}),
			PrefixDescriptor: nlriData["prefixDescriptor"].(map[string]interface{}),
		}, nil
	default:
		return nil, fmt.Errorf("不支持的NLRI类型: %s", nlriType)
	}
}

// parseNLRI 解析NLRI的具体类型和数据（转换为map便于访问字段）
func parseNLRI(nlri *api.NLRI) (typeName string, data map[string]interface{}, err error) {
	// 将protobuf消息转换为JSON，再解析为map（便于动态访问字段）
	jsonBytes, err := protojson.Marshal(nlri.GetLsAddrPrefix().Nlri)
	if err != nil {
		return "", nil, fmt.Errorf("NLRI序列化失败: %w", err)
	}

	var nlriMap map[string]interface{}
	if err := yaml.Unmarshal(jsonBytes, &nlriMap); err != nil {
		return "", nil, fmt.Errorf("NLRI反序列化失败: %w", err)
	}

	// 从@type字段提取类型名（如"type.googleapis.com/gobgpapi.LsNodeNLRI" -> "LsNodeNLRI"）
	typeURL, ok := nlriMap["@type"].(string)
	if !ok {
		return "", nil, errors.New("NLRI中缺少@type字段")
	}
	typeName = typeURL[strings.LastIndex(typeURL, ".")+1:]

	return typeName, nlriMap, nil
}

// parseLsAttribute 从Pattrs中提取LsAttribute属性
func parseLsAttribute(pattrs []*api.Attribute) (map[string]interface{}, error) {
	for _, attr := range pattrs {
		if attr == nil {
			continue
		}

		// 将Attribute转换为map，判断是否为LsAttribute
		jsonBytes, err := protojson.Marshal(attr)
		if err != nil {
			continue // 非目标属性，跳过
		}

		var attrMap map[string]interface{}
		if err := yaml.Unmarshal(jsonBytes, &attrMap); err != nil {
			continue
		}

		// 匹配LsAttribute的类型标识
		if attrType, ok := attrMap["@type"].(string); ok && attrType == "type.googleapis.com/gobgpapi.LsAttribute" {
			return attrMap, nil
		}
	}

	return nil, errors.New("未找到LsAttribute属性")
}
